<template>
	<view class="vi_notify">
		<vi-transition v-if="(useMask||tempMask)&&maskAct" mode="fade" :forceDuration="300" :styles="maskStyle" :show="maskState"/>
		<!-- <view class="vi_notify_mask" :style="maskStyle" v-if="useMask&&dataList.length"></view> -->
		<view class="vi_notify_frame" :style="mainStyle">
			<view class="vi_notify_row" :class="[item.class, 'vi_notify_id'+item.id]" :style="{'padding':item.spaceOutside}" v-for="(item,index) in dataList" :key="item.id">
				<!-- 正常模式 -->
				<view v-if="!item.separation">
					<vi-style-controller
						:type="item.type"
						:color="item.color"
						:plain="item.plain"
						:radius="item.radius"
						:borderWidth="item.borderWidth"
						:borderType="item.borderType"
						:shadow="item.shadow"
						borderBox
						active>
						<view class="vi_notify_cell" :style="{'padding':item.spaceInside, 'justify-content':item.left?'flex-start':'center'}">
							<text class="vi_notify_icon iconfont" :class="item.icon" :style="{'order':item.iconReverse?2:1}" v-if="item.icon"></text>
							<view class="vi_notify_msg" :style="{'order':item.iconReverse?1:2}" v-html="item.msg"></view>
						</view>
					</vi-style-controller>
				</view>
				<!-- 分离模式 -->
				<view v-else class="vi_notify_separationBox" :class="item.type=='black'?'vi_notify_black':'vi_notify_white'"
					:style="{
						'border-width':item.borderWidth,
						'border-style':item.borderType,
						'border-radius':item.radius,
						'box-shadow':item.shadow,
					}">
					<view class="vi_notify_cell" :style="{'padding':item.spaceInside, 'justify-content':item.left?'flex-start':'center'}">
						<view class="vi_notify_icon">
							<vi-style-controller
								:type="item.type"
								:color="item.color"
								:plain="item.plain"
								:radius="item.radius"
								:borderWidth="item.borderWidth"
								:borderType="item.borderType"
								borderBox
								active>
								<text class="iconfont" :class="item.icon" :style="{'order':item.iconReverse?2:1}"></text>
							</vi-style-controller>
						</view>
						<view class="vi_notify_msg" :style="{'order':item.iconReverse?1:2}">
							<vi-style-controller
								control="text"
								:type="item.textType"
								:color="item.textColor"
								inline
								active>
								<view v-html="item.msg"></view>
							</vi-style-controller>
						</view>
					</view>
				</view>
			</view>
		</view>
	</view>
</template>

<script>
	import custom from "./options.js"
	export default {
		name:"",
		props: {
			//位置，可选top、bottom、center
			point:{
				type:[String,null],
				default:""
			},
			//头部向下偏移量，point为top时有效
			//偏移可带单位，px、rpx、em、vh、%(等同vh)
			top:{
				type:[String,Number,null],
				default:""
			},
			//底部向上偏移量，point为bottom时有效
			bottom:{
				type:[String,Number,null],
				default:""
			},
			//通知窗宽度，top、bottom默认100%，center默认50%。空值使用默认
			width:{
				type:[String,null],
				default:""
			},
			//使用遮罩，注意只能等到通知结束取消遮罩，期间不能触发点击操作
			useMask:{
				type:[Boolean,null],
				default:false
			},
			//遮罩背景
			bgMask:{
				type:[String,null],
				default:""
			},
			//层级，比popup高，比headbar低
			zIndex:{
				type:[Number,null],
				default:null
			},
			statusTop:{
				type:[Number,null],
				default:0
			}
		},
		data(){
			return {
				safeAreaInsets:{},
				transition:300,		//过渡时间，须和css的animation时间一致
				stayTime:3000,		//停留时间
				id:10,				//id自增
				dataList:[],
				dicSet:{
					type:"primary",
					color:"",
					borderWidth:0,
					borderType:"solid",
					plain:false,
					radius:"0.5em",
					left:true,				//左对齐
					spaceInside:["0.5em", "0.75em", "0.5em", "0.75em"],
					spaceOutside:"0.75em",	//只控制左右边距
					rowSpace:"0.5em",		//行间距，只控制下边距
					icon:"icon-information",
					iconSize:"1em",			//图标大小
					iconReverse:false,		//图标与文字反向
					shadow:"0 1px 0.25em rgba(0, 0, 0, .2)",	//外框阴影，同css格式
					//图标与内容分离
					//开启后通知条底色固定，边框色固定，文字色由textType和textColor控制
					//type、color、plain控制只应用到图标。非plain状态图标大小为1.2em
					//图标圆角由iconRadius控制
					separation:true,
					textType:"",
					textColor:"",
					iconRadius:"50%",
				},
				shiftY:0,	//关闭通知时高度偏移
				maskAct:false,		//遮罩激活
				maskState:false,	//遮罩启动
				maskTimer:null,		//遮罩定时器，用于关闭
				tempMask:false,		//临时遮罩，与useMask同级
			}
		},
		computed: {
			setting(){
				return {
					point: this.point ||"top",
					zIndex: this.$api.isValue(this.zIndex)? this.zIndex :110,
				}
			},
			//外框样式对象，分步处理
			mainStyleObj(){
				let res ={
					"z-index":this.setting.zIndex
				};
				let temp =[],
					width = this.width,
					point = this.setting.point;
				if(["top","bottom"].includes(point)){
					let val = this[point],
						saveVal = this.safeAreaInsets[point];
					res["width"] = width ||"100%";
					
					if(saveVal){
						temp.push(saveVal +"px")
					}
					if(val){
						if(this.$api.isNumber(val,true)){
							val += "px"
						}
						if(val.startsWith("calc(")){
							val = this.$api.getCalc(val)
						}else if(val.endsWith("%")){
							val = val.replace("%","vh")
						}
						temp.push(val)
					}
					if(!temp.length){
						temp.push("0px")
					}
					res[point] = `calc(${temp.join(" + ")})`
				}else{//中间
					res["max-width"] =  width ||"50%";
				}
				return res
			},
			//外框样式
			mainStyle(){
				let res = this.mainStyleObj;
				let trans = ["-50%",""];
				if(!["top", "bottom"].includes(this.setting.point)){
					trans[1] ="-100%";
				}else{
					trans[1] = this.shiftY +"px";
					if(this.shiftY !==0){
						res["transition"] = "0.3s"
					}
				}
				res["transform"] = `translateX(${trans[0]}) ` +(trans[1]? `translateY(${trans[1]})` :"");
				return this.$api.objToStr(res)
			},
			//遮罩样式
			maskStyle(){
				let res ={
					"position": "fixed",
					"bottom": 0,
					"top": 0,
					"left": 0,
					"right": 0,
					"z-index":this.setting.zIndex -1,
					"background-color": this.bgMask ||"rgba(0,0,0,0)"
				};
				return this.$api.objToStr(res)
			}
		},
		methods: {
			createId(){
				return ++this.id
			},
			open(msg, options={}, tempMask){
				if(typeof(options)=="string"){
					options = custom[options] ||{}
				}
				if(tempMask){
					this.tempMask =true
				}
				let newObj = Object.assign({msg},this.dicSet,options);
				newObj["id"] = this.createId();
				//固定只有一种黑色样式，黑底白字，半透明
				if(newObj.type=="black"){
					newObj.separation =true
				}
				//分离模式处理border宽
				if(newObj.separation){
					newObj["borderWidth"] = newObj.borderWidth +(this.$api.isNumber(newObj.borderWidth,true)?"px":"");
				}
				//top、bottom且宽度为100%时，圆角置0
				let radius = newObj.radius;
				let tempR,
					point = this.setting.point;
				if(radius){
					tempR = this.$api.isArray(radius)? radius :[radius,radius,radius,radius];
					if(["top","bottom"].includes(point)&&!newObj.width){
						tempR = [0]
					}
					//转换为css格式
					newObj["redius"] =tempR.join(" ")
				}
				//对spaceInside处理，使符合css字符串格式
				let spIn = newObj.spaceInside;
				if(spIn){
					newObj["spaceInside"] = this.$api.isArray(spIn)? spIn.join(" ") :spIn;
				}
				//对spaceOutside处理，使符合css格式
				let spOut = newObj.spaceOutside ||0;
				let spRow = newObj.rowSpace ||0;
				if(!this.$api.isArray(spOut)){
					spOut = [0,spOut,0,spOut];
				}else{
					spOut[0] = 0;
					spOut[2] = 0;
				}
				spOut[0] = point=="bottom"? 0:spRow;
				spOut[2] = point=="bottom"? spRow:0;
				newObj["spaceOutside"] = spOut.join(" ");
				
				if(point=="bottom"){
					newObj["class"] = "vi_notify_showReverse"
					this.dataList.unshift(newObj)
				}else{
					newObj["class"] = "vi_notify_show"
					this.dataList.push(newObj)
				}
				//查询当前通知高度
				this.$nextTick(async ()=>{
					let info = await this.getItemHeight(newObj.id);
					if(info){
						newObj["offSet"] =info.height
					}
				})
				//遮罩有延时关闭，取消
				if(this.maskTimer){
					clearTimeout(this.maskTimer);
					this.maskTimer =null;
				}
				this.maskAct =true;
				this.maskState =true;
				//延时关闭
				newObj["closeTimer"] = setTimeout(()=>{
					this.close(newObj.id);
				},this.stayTime)
			},
			//关闭，有默认顺序
			close(id){
				if(id){
					let item = this.$api.arrFind(this.dataList,{key:"id",value:id,format:"item"});
					if(!item){
						console.log("通知关闭失败，找不到目标");
						return
					}
					//处理关闭，查询列表高度
					if(this.setting.point=="bottom"){
						item["class"] = "vi_notify_closeReverse";
					}else{
						item["class"] = "vi_notify_close";
					}
					//查询关闭状态，设置列表偏移
					item["closing"] =1;
					let list =this.dataList;
					let Y =0;
					for(let i=0,len=list.length; i<len; i++){
						if(list[i].closing){
							Y += list[i].offSet ||0
						}
					}
					this.shiftY = this.setting.point=="bottom"? Y :-Y;
					//动画完成后判断是否清空列表
					setTimeout(()=>{
						item["closing"] =2;
						//如果列表全部为关闭，则清空列表
						let end=true;
						for(let it of list){
							if(it.closing !=2){
								end =false;
								break;
							}
						}
						if(end){
							this.shiftY = 0;
							this.dataList.splice(0);
							this.maskState =false;
							this.maskTimer =setTimeout(()=>{
								this.maskAct =false;
								this.tempMask =false;
							},300)
						}
					},this.transition)
				}
			},
			//获取通知高度
			getItemHeight(id){
				const query = uni.createSelectorQuery().in(this);
				return new Promise((resolve, rej) => {
					query.select('.vi_notify_id'+id).boundingClientRect(data => {
						resolve(data);
					}).exec();
				})
			}
		},
		mounted() {
			try {
				const res = uni.getSystemInfoSync();
				this.safeAreaInsets = res.safeAreaInsets;
				if(this.statusTop){
					this.safeAreaInsets["top"] = this.statusTop
				}
			} catch (e) {
				console.log("获取系统信息失败",e);
			}
		}
	}
</script>

<style lang="scss">
.vi_notify{
	.vi_notify_mask{
		position: fixed;
		top: 0;
		left: 0;
		right: 0;
		bottom: 0;
		z-index: 98;
	}
	.vi_notify_frame{
		position: fixed;
		z-index: 99;
		left: 50%;
	}
	.vi_notify_row{
		transition: 0.3s;
	}
	.vi_notify_cell{
		display: flex;
		align-items: center;
		width: 100%;
	}
	.vi_notify_white{
		color: #666;
		background-color: #fff;
		border-color: #eee;
	}
	.vi_notify_black{
		color: rgba(255, 255, 255, .8);
		background-color: rgba(0, 0, 0, .65);
		border-color: rgba(0, 0, 0, .65);
	}
	.vi_notify_msg{
		flex-grow: 1;
	}
	.vi_notify_icon{
		margin-right: 0.5em;
		font-size: 120%;
	}
	.vi_notify_close{
		opacity: 0;
		transform: translate(0, -60rpx);
	}
	.vi_notify_closeReverse{
		opacity: 0;
		transform: translate(0, 60rpx);
	}
	.vi_notify_show{
		animation: ani 0.3s;
	}
	.vi_notify_showReverse{
		animation: aniReverse 0.3s;
	}
	@keyframes ani {
		0% {
			opacity: 0;
			transform: translate(0, -60rpx);
		}
		100% {
			opacity: 1;
			transform: translate(0, 0rpx);
		}
	}
	@keyframes aniReverse {
		0% {
			opacity: 0;
			transform: translate(0, 60rpx);
		}
		100% {
			opacity: 1;
			transform: translate(0, 0rpx);
		}
	}
}
</style>